import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.List;

/**
 * @author TrinhNX
 * @author TrinhNX
 * @start_date	: 2015/04/20
 * @end_date 	:
 * Đậu xanh quên check null, khi mà giả sử cái
 * array /list ko được khởi tạo liền nhau :v ví dụ index array từ 1 :v
 */
public final class Common {
	private static final String DATA_FOLDER = "data";

	/**
	 * Print out the list (note object should implement the toString())
	 * 
	 * @param list
	 */
	public static void printList(List<? extends Object> list) {
		for (Object object : list) {
			if (object != null)
				System.out.println(object);
		}
	}

	/**
	 * Print out the array
	 * 
	 * @param list
	 */
	public static <T extends Object> void printArray(T[] list) {
		// It is no need to do this, waste of timeee
		for (T t : list) {
			if (t != null)
				System.out.println(t);
		}
	}

	/**
	 * Print out the array
	 * @param array
	 */
	public static void printArray(int[] array, final String delimeter) {
		for (int a : array) {
			System.out.print(a + delimeter);
		}
	}
	
	/**
	 * Print out the 2D array
	 */
	public static void printArray(int[][] array, final String delimeter) {
		for (int i = 0; i < array.length; i++) {
			printArray(array[i], delimeter);
			System.out.println("\n");
		}
	}

	/**
	 * Write a list into file
	 * 
	 * @param list
	 */
	public static <T> void writeList(final List<T> list, final File fileOut) {
		try {
			PrintWriter pw = new PrintWriter(new FileOutputStream(fileOut));
			for (T t : list) {
				if (t != null)
					pw.append(t.toString());
			}
			pw.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Write a list into file
	 * 
	 * @param array
	 */
	public static <T> void writeArray(final T[] array, final File fileOut) {
		if (fileOut == null)
			return;

		try {
			// Not exist, create
			// Exist, create new one :v :v
			fileOut.createNewFile();
			PrintWriter pw = new PrintWriter(new FileOutputStream(fileOut));
			for (T t : array) {
				if (t != null) {
					pw.write(t.toString() + "\r\n");
				}
			}
			pw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Write a list into file
	 * 
	 * @param array
	 */
	public static void writeArray(final int[] array, final File fileOut) {
		if (fileOut == null)
			return;

		try {
			// Not exist, create
			// Exist, create new one :v :v
			fileOut.createNewFile();
			PrintWriter pw = new PrintWriter(new FileOutputStream(fileOut));
			for (int t : array) {
				pw.write(t + "\r\n");
			}
			pw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Read a file and return the string content, well, not so useful ?
	 * 
	 * @param fileName
	 *            default location is data/filename
	 * @return
	 * 
	 */
	public static String readFile(final String fileName) throws IOException {
		StringBuilder sb = new StringBuilder(10);
		FileReader fr = new FileReader(new File(DATA_FOLDER + File.separator
				+ fileName));
		BufferedReader br = new BufferedReader(fr);
		String line;
		while ((line = br.readLine()) != null) {
			sb.append(line);
		}
		br.close();
		fr.close();
		return sb.toString();
	}

	/**
	 * Return the prime factor array of N (N>1)
	 * @param value
	 * @return
	 * TrinhNX 04/20
	 * EX: 7 -> [7]
	 *     4 -> [2, 2]
	 *     15-> [3, 5]
	 */
	public static int[] primeFactor(int value) {
		/**
		 * If value is invalid => error
		 * If value is prime => return itself
		 * Else return array of factors
		 */
		final int MAX = 64;
		int index = 0;
		int[] result = new int[MAX];
		if (value < 2) {
			throw new InvalidParameterException("I dont play with n=" + value);
		}

		if (isPrime(value)) {
			return new int[] { value };
		}
		// Initialize with 5 values
		int i = 2;
		while (i <= value) {
			if (value % i == 0) {
				value = value / i;
				result[index++] = i;
			} else {
				i++;
			}
		}
		// return convertToArray(mList, 0);
		return Arrays.copyOf(result, index);
	}

	/**
	 * Check a value is prime or not
	 * @param value > 1
	 * @return
	 * TrinhNX 04/20
	 */
	public static boolean isPrime(final int value) {
		//		if (value <2) {
		//			throw new InvalidParameterException("Don't mess with me: n = " + value);
		//		}
		//		System.out.println(value);
		if (value < 2)
			return false;
		for (int i = 2; i * i <= value; i++) {
			if (value % i == 0)
				return false;
		}
		return true;
	}

	/**
	 * Convert a list to an array with start index
	 * @param source
	 * @param startIndex
	 * @return
	 */
	public static int[] convertToArray(List<Integer> source,
			final int startIndex) {
		if (source == null)
			throw new NullPointerException("Source is null");
		final int[] out = new int[source.size()];
		int i = startIndex;
		for (Integer data : source) {
			out[i++] = data;
		}
		return out;
	}

	/**
	 * Return greatest common divisor
	 * @param a
	 * @param b
	 * @return
	 * Implement as Binary_GCD_algorithm
	 */
	public static int gcd(int a, int b) {
		if (a < 2 || b < 2)
			throw new InvalidParameterException("Solve yourself");
		if (a % b == 0)
			return b;
		if (b % a == 0)
			return a;
		int d = 0;
		while ((a & 1) == 0 && (b & 1) == 0) {
			a = a >> 1;
			b = b >> 1;
			d++;
		}
		while (a != b) {
			if ((a & 1) == 0 && (b & 1) == 1) {
				a = a >> 1;
			} else if ((a & 1) == 1 && (b & 1) == 0) {
				b = b >> 1;
			} else if (a >= b) {
				a = (a - b) >> 1;
			} else
				b = (b - a) >> 1;
		}
		return b * (int) Math.pow(2, d);
	}

	/**
	 * Deal only with positive 
	 * @author		: TrinhNX
	 * @param value
	 * @return
	 * @start_date	: 2015/04/24
	 * @end_date	:
	 */
	public static int numberLength(int value) {
		int l;
		for (l = 0; value > 0; ++l) {
			value /= 10;
		}
		return l;

	}

	/**
	 * Return the 10^n (n >= 0)
	 * @author		: TrinhNX
	 * @param power
	 * @return
	 * @start_date	: 2015/04/24
	 * @end_date	:
	 */
	public static int power10(int power) {
		int result = 1;
		while (power-- > 0) {
			result *= 10;
		}
		return result;
	}

	/**
	 * Swap from i index with j index of array data 
	 * @author		: TrinhNX
	 * @param data
	 * @param i
	 * @param j
	 * @start_date	: 2015/05/08
	 * @end_date	:
	 */
	public static void swap(final int[] data, final int i, final int j) {
		int temp = data[i];
		data[i] = data[j];
		data[j] = temp;
	}

	/**
	 * Swap an integer array from start -> end index
	 * Ex: Array 0, 3, 4, 2, 5
	 * swapRange(1, 3) => 0, 2, 4, 3, 5
	 * swapRange(1, 4) => 0, 5, 2, 4, 3
	 * @author		: TrinhNX
	 * @param data
	 * @param start
	 * @param end
	 * @start_date	: 2015/05/08
	 * @end_date	:
	 */
	public static void swapRange(final int[] data, final int start,
			final int end) {
		// TODO:
	}

}
